// ------------------------------------------------------------------------------------
// REVISION LOG ENTRY
//
//	File name  : https://js-extension-afx.googlecode.com/svn/trunk/jsafx-impl.js
// Revision By: (C) Copyright 2014 Hiroyuki Tominaga, All Rights Reserved.
//
//	Revised on : 2014-06-08 16:04:51
//	Summary    : extract from jsafx.js
//
// ------------------------------------------------------------------------------------

var $ = $ || {};
if( !$.noop ) {
	$.noop = function(){};
	// Simple implementation...
	$.extend = function extend(destination, source) {
		for (var property in source)
			destination[property] = source[property];
		return destination;
	};
};

/* specified package name. */
// NOTE: [2010-11-26 12:23:08]
// var 付で宣言すると delete が失敗する.
//
window["_PRIME_PACKAGE_NAME_"] = window["_PRIME_PACKAGE_NAME_"] || "jsafx";


/* ------------------------------ Start define the "jsafx" name space. ------------------------------ */
(function(name_space)
{

	/*
	*	format: replace the "${<property name>}" form to value.
	*
	* @param pair_object: like { title: "this is a title.", content: "contents" }
	* @param keys: like ["title", "content"], this is a optional. collect automatically
	* @param a_regexp: like ["\\$\\{", "\\}"], default is ["\\$\\{", "\\}"]
	*/
	/*
		tag array of strings around the regular expression
		tagを囲む正規表現の文字列の配列
	*/
	//String.FORMAT_TYPE_DOLLAR_BRACE = 1;
	//String.FORMAT_TYPE_BRACE_DOLLAR = 2;	/* xslt に対する互換性を考慮しての実装 */
	var _AORF = ["\\$\\{", "\\}"]; // defautl array_of_regexpfragment
	// note: 2014-06-28 23:41:59 jsafx.util.cp に依存するのでこちらに移動.
	String.prototype.format = function (pair_object, keys, a_regexp)
	{
		if(!keys)
			keys = jsafx.util.cp(pair_object);
		if( typeof(a_regexp) === "undefined" )
			a_regexp = _AORF;

		var fmt = this;
		for (
			var size = keys.length, index = 0; index < size; //index++
		) {
			var value = pair_object[ keys[index] ];
			if(value && typeof value !== "string")
				value += ""; // convert to string...

			//block = "${" + keys[index++] + "}";
			var exp = new RegExp(a_regexp[0] + keys[index++] + a_regexp[1], "g");
			if( fmt.search(exp) !== -1 )
				fmt = fmt.replace(exp, value);
		}

		return fmt;
	};

	function generateId(length)
	{
		var id = "_uid_";
		var id_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-";
		var l = id_chars.length;
		while (length--) {
			id += id_chars[ Math.floor(Math.random() * l) ];
		}
		return id;
		//"closure_uid_" + Math.floor(Math.random() * 2147483648).toString(36);
	}

	/* need for oop functions */
	/*var _QNAME_ = generateId(8);
	var _EXTENDED_ = generateId(8);
	var _CLASSES_ = generateId(8);*/
	var _QNAME_ = "_QNAME_";
	var _EXTENDED_ = "_EXTENDED_";
	var _CLASSES_ = "_CLASSES_";
	// ----------------------------------- oop functions. --------------------------------
	/*
	[2010-11-28 07:32:52]
		super class の method override が適用されていなかったので
		特別に定義.
			--> [2010-11-28 07:36:23] 結果 OK!
	*/
	//
	// @param _this  prototype object or actual instance.
	// @param _super prototype object or actual instance.
	//
	// @return _this
	//
	function extendOverride(_this, _super)
	{
		var _this_proto =
			( typeof _this.prototype === "object" )? _this.prototype: _this;

		if ( typeof _super.prototype === "object" )
			_super = _super.prototype;

		for (var p in _super) {
			if(!_this_proto[p]) // has not property?
				_this_proto[p] = _super[p];
		}
		return _this;
	};
	//
	// verify Inheritance.
	//
	//
	function verifyInheritance
	(
		this_constructor, super_constructor, ns
	) {
		if( !this_constructor[_EXTENDED_] )
		{
			extendOverride(
				this_constructor, super_constructor
			)[_EXTENDED_] = true;
			//this_constructor[_EXTENDED_] = true;
			/* make qualified name static. */
			assignCanonicalName(this_constructor, ns);
		}
	};
	//
	//make qualified name as static.
	//
	// @param instance	:
	// @param ns		:name space specified.
	//
	function assignCanonicalName(this_constructor, ns) {
		return (this_constructor[_QNAME_] =  ns + "." + this_constructor.name);
	}
	function lookUpCanonicalName(this_constructor) {
		return this_constructor[_QNAME_];
	}
	//
	// @param instance  :
	// @param list		:
	//
	function assignInheritance(_this, list) {
		if(!_this.constructor[_CLASSES_])
			_this.constructor[_CLASSES_] = list;
	}
	function isInheritanceAssigned(this_constructor) {
		return isEnumerable( this_constructor[_CLASSES_] );
	}
	function lookUpInheritanceList(this_constructor) {
		return this_constructor[_CLASSES_];
	}
	//
	//
	//
	function prependQName2Arguments(this_constructor, args, ns)
	{
		!args.unshift && ( args = makeArrayFrom(args) ); /* means args is arguments object. */
		var this_name = this_constructor[_QNAME_];
		if(this_name === undefined)
			this_name = assignCanonicalName(this_constructor, ns);

		args.length && args.unshift(this_name) ||	/* means args has parameter. */
							args.push(this_name);	/* means args has not parameter. */
		return args;
	}
	/*
	[2010-11-25 11:17:32]
		継承するクラスは必ずこの関数を呼んで低レベルの初期化を行います。
		Initialize the class that inherits from the low level of this function must be called.
	*/
	//
	// @param instance			:current instance of object. MUST this
	// @param this_constructor	:
	// @param super_constructor	:
	// @param args				:must be arguments object.
	// @param ns				:name space specified.
	//
	function initializeAtom
	(
		instance,
		this_constructor, super_constructor,
		args, ns
	) {
		args = prependQName2Arguments(this_constructor, args, ns);
		instance.constructor = this_constructor;
		if(typeof(super_constructor) === "function")
			super_constructor.apply(instance, args);

		verifyInheritance(
			this_constructor, super_constructor, ns
		);
	}
	//
	// @param args :must be arguments object.
	//
	function makeArrayFrom(args)
	{
		var arry = [];
		for(var i = 0; i < args.length; i++)
			arry.push(args[i]);

		return arry;
	}

	function isEnumerable(any) {
		// ("length" in any) is mistake
		//return any !== undefined && ("length" in any);
		return typeof any === "object" && any.length > 0;
	}
	//
	// Afeedvis = jsafx.oop.createInstance("jsafx.IFeedVisitor", "video", "8e2wMY4yNbo");
	//
	//		actual_args: --> "jsafx.IFeedVisitor", "video", "8e2wMY4yNbo"
	//		actual_args.shift(): --> "video", "8e2wMY4yNbo"
	//		return new constructor(["video", "8e2wMY4yNbo"]);
	//
	//
	/* [2010-11-29 07:29:55]
		object 構築時に parameter を渡したいときにはこの function を使うこと.
	*/
	function createInstance(qname/*, ...*/)
	{
		//var actual_args = makeArrayFrom(arguments);
		//var constructor = eval(actual_args.shift());
		//return new constructor(actual_args);
		/* NOTE: remove qname at this point. */
		var constructor = eval(  Array.prototype.shift.call(arguments)  );
		return new constructor(arguments);
	}

	/* ほかの function が意味もなくnewInstance を継承してしまうので NG! */
	//Function.prototype.newInstance = function() { return new this(arguments); };


	/* [2010-11-30 06:38:47] proposed.
		this class is low level.
	*/
	var _PACKAGE_EXTEND_METHOD_ = "addStaticProperties";
	//
	// @param n	: name of this package.
	// @param v	: @optional, the version string. default is "0.0.1:beta" means state of proposed.
	// @param static_properties	: @optional, the static properties. (function, constructor etc.
	//
	function Package(n, v, static_properties)
	{
		// public
		this.packageName = n;
		this.version = v? v: "0.0.1:beta";

		// usage for static properties.
		{
			var type = typeof(static_properties);
			if(
				type !== "undefined" && type === "object"
			) extendOverride(this, static_properties);
		}
	}

	Package.prototype = {
		// utility method.
		//addStaticProperties:
	};
	Package.prototype[_PACKAGE_EXTEND_METHOD_] = function (static_properties) {
		extendOverride(this, static_properties);
	};


	var W = (window || self);
	//
	//	[2010-11-25 09:56:51] define package name space.
	//
	/* check exsits */
	/* [2010-12-02 10:22:15] Web Workers 用に 書き直す. (window object は存在しない) */
	if(W[name_space] instanceof Package)
		return;

	W[name_space] = new Package(name_space, "0.0.2:beta");

	/* */
	var acutual_ns = W[name_space];//eval(name_space);
	/*if ( acutual_ns.version ) {
		return;
	}*/

	acutual_ns.generateId = generateId;
	//
	//acutual_ns.version = "0.0.2:beta";


	// ----------------------------------- helper functions. --------------------------------

	//[2010-11-25 11:51:18]
	//
	// export functions:
	//
	//	generateId
	//		@param length : the generate id length.
	//
	//	assignQName		(make qualified name as static.
	//		@param this_constructor	:
	//		@param ns				:name space specified.
	//	lookUpQName		(get qualified name as static.
	//		@param this_constructor	:
	//
	//	assignInheritance
	//		@param instance	:the class instance.
	//		@param list		:must be array object of inheritance list.
	//	isInheritanceAssigned
	//		@param this_constructor	: the class constructor.
	//	lookUpInheritanceList
	//		@param this_constructor	: the class constructor.
	//
	//	initAtom	:note! extend use this_constructor super_constructor prototype
	//		@param instance			:current instance of object. MUST this
	//		@param this_constructor:
	//		@param super_constructor:
	//		@param args				:must be arguments object.
	//		@param package ns		:name space specified.
	//	extendOverride
	//		@param _this : the this object or this prototype object.
	//		@param _super : the super object or super prototype object.
	//	createInstance		jsafx.oop.createInstance("jsafx.IFeedVisitor", "video", "8e2wMY4yNbo");
	//		@param qname : qualified name. like "jsafx.IFeedVisitor"
	//		@param args : unlimited arguments. like "video", "8e2wMY4yNbo", 2, true...
	//
	//	makeArrayFrom
	//		@param args : must be arguments object.
	//
	//
	acutual_ns.oop = new Package(name_space + ".oop");
	acutual_ns.oop[_PACKAGE_EXTEND_METHOD_](
	{
		generateId: generateId,

		assignQName: assignCanonicalName,
		lookUpQName: lookUpCanonicalName,

		assignInheritance: assignInheritance,
		isInheritanceAssigned: isInheritanceAssigned,
		lookUpInheritanceList: lookUpInheritanceList,

		initAtom: initializeAtom,
		extendOverride: extendOverride,
		createInstance: createInstance,	/* (qname, ...) */

		makeArrayFrom: makeArrayFrom,

		Package: Package
	});

	/* reserved package. */
	acutual_ns.model	= new Package(name_space + ".model");
	/* widget gadget */
	acutual_ns.view		= new Package(name_space+ ".view");
	acutual_ns.ctrl		= new Package(name_space + ".ctrl");
	acutual_ns.sys		= new Package(name_space + ".sys");

	acutual_ns.io		= new Package(name_space + ".io");
	acutual_ns.net		= new Package(name_space + ".net");
	acutual_ns.logic	= new Package(name_space + ".logic");
	acutual_ns.storage	= new Package(name_space + ".storage");
	acutual_ns.util		= new Package(name_space + ".util");



	// -----------------------------------------------------------------------------
	//
	//	Name space of acutual_ns.sys
	//
	// -----------------------------------------------------------------------------
	/*
	[2010-11-29 08:12:31] proposed.

	*/
	acutual_ns.sys[_PACKAGE_EXTEND_METHOD_](
	{
		TimerQueue: function TimerQueue() {
			;
		}
	});

	// -----------------------------------------------------------------------------
	//
	//	Name space of acutual_ns.model.dom
	//
	// -----------------------------------------------------------------------------
	//
	//	Export acutual_ns.model.dom method, classes
	//
	acutual_ns.model.dom = {
		//
		// @param tag	: the element tag name like "div".
		// @param attrs	: like { "id": "id12345" , style: "text-align: center;" }
		// @param doc   : actual document if need.
		//
		// @return 	the plain dom object.
		//
		createElement: function(tag, attrs, doc) {
			// !tagName && (tagName = "div");
			!doc && (doc = window.document);
			var node = document.createElement(tag), attr;
			for (attr in attrs) {
				if (attrs.hasOwnProperty(attr)) {
					node.setAttribute(attr, attrs[attr]);
				}
			}
			return node;
		}
	};

	// -----------------------------------------------------------------------------
	//
	//	Name space of acutual_ns.view.ui
	//
	// -----------------------------------------------------------------------------

	//
	// [2010-12-12 10:00:46] added.
	//	 gadgetWindow object
	//
	// @param attrs		: like [ { name: "class", value: "class12345" }, { name: "style", value: "text-align: center;" }]
	// @param tagName	: the element tag name default is "div".
	// @param id		: the element id. When not specified it, will generate by "generateId(8)"
	//
	// !! ------------------ Required jQuery UI draggable
	//
	function gadgetWindow(tagName, id, attrs)
	{
		!tagName && (tagName = "div");
		!id && (id = generateId(8));

		this.tagName = tagName;
		this.id = id;

		attrs.id = id;
		this.dom_obj = createE(tagName, attrs);
	};
	gadgetWindow.prototype =
	{
		setContent: function(content) {
			var child = this.dom_obj.children.length > 0? this.dom_obj.children[0]: undefined;
			if(!child)
				this.dom_obj.innerHTML = content;
			else
				child.innerHTML = content;
		},

		show: function() {
			this.dom_obj.style.visibility = "visible";
		},
		isShowing: function() {
			return this.dom_obj.style.visibility === "visible";
		},
		hide: function() {
			this.dom_obj.style.visibility = "hidden";
		},
		draggable: function() {
			$(this.dom_obj).draggable();
			// see jsafx $.dragWindow(); easy drag move
			/*$(this.dom_obj).dragWindow(false, function(e) {
				console.log("dragWindow, type=%s, id=%s, tag=%s", e.type, e.target.id, e.target.tagName);
			});*/
		},

		setParent: function(p) {
			var dom = this.dom_obj;
			if(dom.parentNode !== null)
				dom.parentNode.removeChild(dom);

			p.appendChild(dom);
		},
		addChildren: function(c) {
			this.dom_obj.appendChild(c);
		}
	};
	//
	//	Export acutual_ns.view.ui method, classes
	//
	acutual_ns.view.ui = {
		gadgetWindow: gadgetWindow
	};


	// -----------------------------------------------------------------------------
	//
	//	Name space of acutual_ns.model.net
	//
	// -----------------------------------------------------------------------------
	var _FDOBJ_ = "_FDOBJ_";//generateId(6);
	// currently support is "json" only.
	function FeedEntry(feed_entry, alt)
	{
		initializeAtom(
			this,
			acutual_ns.model.net.FeedEntry,
			acutual_ns.AfxObject,
			arguments, name_space + ".model.net"
		);
		if(arguments.length > 0 && isEnumerable(arguments[0]))
		{
			var actualArgs = arguments[0];
			this[_FDOBJ_] = actualArgs[0];
		}
		// xml, json, ...
		this.alt = "json";//alt? alt: "json";
	}

	FeedEntry.prototype = {
		_orders: undefined,
		// for extend class.
		getFeedObject: function getFeedObject() { return this[_FDOBJ_]; },
		//
		// @param o :must be feed.entry object.
		//
		setFeedObject: function setFeedObject(o) {
			this[_FDOBJ_] = o;
		},
		//
		// @param param :must be separated by /\||\n|,| /g. ().split(/\||\n|,| /g)
		//
		setOrder:  $.noop,
		getOrder: function getOrder(param) {
			return this._orders;
		},
		getTaggedValue: $.noop
	};

	//
	//	Export acutual_ns.model.net classes
	//
	acutual_ns.model.net = new Package(name_space + ".model.net", "", {
		FeedEntry: FeedEntry
	});

	//
	// @param jsonUrl
	// @param handler
	// @param error_handler
	//
	// @param [onprogress]	this is mozilla only
	// @param [onload]		this is mozilla only
	// @param [onerror]		this is mozilla only
	//
	// usage: acutual_ns.oop.createInstance("jsafx.net.XhrJson", url, handler, ehandler, [onprogress], [onload], [onerror]);
	//
	// NOTE: This class automatically adds a parameter "&callback=redirect"
	//		 and this class is async.
	//
	function XhrJson(/*jsonUrl, handler, error_handler*/)
	{
		initializeAtom
		(
			this,
			acutual_ns.net.XhrJson,
			acutual_ns.AfxObject,
			arguments, name_space + ".net"
		);

		if(arguments.length > 0 && isEnumerable(arguments[0]))
		{
			var actualArgs = arguments[0];
			this.jsonUrl = actualArgs[0];
			var h = actualArgs[1];
			this.handler = typeof(h) === "function"? h: $.noop;
			h = actualArgs[2];
			this.error_handler = typeof(h) === "function"? h: $.noop;
			//this.xhr = new XMLHttpRequest();
			if( $.browser.mozilla )
			{
				h = actualArgs[3];
				this.xhr_progress = typeof(h) === "function"? h: null;
				h = actualArgs[4];
				this.xhr_load = typeof(h) === "function"? h: null;
				h = actualArgs[5];
				this.xhr_error = typeof(h) === "function"? h: null;
			}

		}

		// [2010-12-09 14:58:09]
		//this._fetching = false;	/* usage for xhr flag */

		this.createXhr = function() {
			var xhr = new XMLHttpRequest();
			var _this = this;
			xhr._fetching = false;	/* usage for xhr flag */

			this._xhr = xhr;
			// [2010-12-09 14:15:22]
			if( $.browser.mozilla )
			{
				xhr.onprogress = this.xhr_progress;
				xhr.onload = this.xhr_load;
				xhr.onerror = this.xhr_error;
			}
			// NOTE 2014-03-01 01:07:56
			// jquery 1.4.4 を使っていたころは問題なかったが,
			// 1.5 以降の version では JQuery.httpSuccess が削除されていいるようで
			// この function の実装が必要だった.

			/*
			リクエストの状態です：

			値	状態	詳細
			0	XMLHttpRequest.UNSENT           open() がまだ呼び出されていない。
			1	XMLHttpRequest.OPENED           send() がまだ呼び出されていない。
			2	XMLHttpRequest.HEADERS_RECEIVED send() が呼び出され、ヘッダーとステータスが通った。
			3	XMLHttpRequest.LOADING          ダウンロード中；responseText は断片的なデータを保持している。
			4	XMLHttpRequest.DONE             一連の動作が完了した。
			*/
			xhr.isSuccess = function isSuccess() {
				var st = this.status;
				return st >= 200 && st < 300 || st === 304;
			};
			/* it's a tricky */
			function redirect(d) { return d; };
			xhr.onreadystatechange = function xhrReadyStateChange( isTimeout )
			{
				if(this.readyState !== XMLHttpRequest.DONE)
					return;

				var status = isTimeout === "timeout" ? "timeout" :
							!this.isSuccess() ? "error" : "success";
				/* [2010-11-28 05:31:42] HTTP 403 はこれで捕まえることができるようになった. */
				try {
					if(!this.responseText && this.status === 0)
						throw new Error("cannot acssess :" + _this.jsonUrl);
					var ret = eval(xhr.responseText);	/* "redirect(<json string>);" */
					var h = _this.handler;
					(typeof(h) === "function") && h(ret, status, this);
				}
				catch(e) { _this.error_handler(e); }
				finally {
					//_this._fetching = false;
					xhr._fetching = false;	/* usage for xhr flag */
					//xhr.onreadystatechange = $.noop;
					/*if( $.browser.mozilla )
					{
						xhr.onprogress = $.noop;
						xhr.onload = $.noop;
						xhr.onerror = $.noop;
					}*/
				}
			};
		}

		// initialize XMLHttpRequest instance.
		this.createXhr();
	}

	XhrJson.prototype = {
		//xhr: undefined,
		//
		// @param url : new request URL of json
		//
		changeUrl: function changeUrl(url) {
			this.jsonUrl = url;
		},
		/*
		void open(
		 in AUTF8String method,
		 in AUTF8String url,
		 [optional] in boolean async,
		 [optional] in AString user,
		 [optional] in AString password
		);
		*/
		//
		// @return XMLHttpRequest object.
		//
		fetchJson: function fetchJson()
		{
			var xhr = this._xhr;
			if(xhr._fetching)
				return;

			xhr._fetching = true;
			/* point: "callback=" とすると error になる */
			xhr.open("GET", this.jsonUrl + "&callback=redirect", true);
			try {
				xhr.send(null);
			} // 403 などの error で access 不可のとき browzer side で例外を catch されてしう...
			catch(e) { this.error_handler(e); }

			return xhr;
		}
	};
	//
	//	Export acutual_ns.net classes
	//
	acutual_ns.net[_PACKAGE_EXTEND_METHOD_]( {
		XhrJson: XhrJson
	});

	//
	// @param arg :must be function <arguments> object.
	//
	// @return : string, format is following.
	//
	//	length = {arguments.length},
	//	callee = {arguments.callee},
	//	values = {arguments[n],arguments[n],arguments[n]...}
	//
	function dumpArguments(arg)
	{
		//return acutual_ns.util.gepwv(arg); // NG...
		var context = {
			length: arg.length,
			caller: arg.caller,
			values: (function() {
				var l = arg.length;
				var arry = new Array(l);
				for(var i = 0; i < l; i++)
					arry[i] = arg[i];
					//arry.push(arg[i]);
				return arry.join(", ");
			})()
		};
		return this.gepwv(context);
	};

	/* [IE, NN6] */
	//
	// @param e :an object (any
	// @param type :result of "typeof" expression. ex: "string", "object", "number"...
	// @param b_sort :Specify whether to sort
	//
	function correctProperties(e, type, b_sort)
	{
		var i = 0;
		var arry = [];//new Array(30);	// allocate 30 slot
		if(type && typeof type === "string") {
			for(var x in e)
			if(typeof e[x] === type)
				arry[i++] = x;
		}
		else {
			for(var x in e)
				arry[i++] = x;
		}
		if(b_sort)
			arry.sort();

		return arry;
	};
	/* [IE, NN6] */
	// 2004年 05月25日 07:51:09
	/**
	 */
	function elementPropertySizeOf(e)
	{
		var i = 0;
		if(typeof(e) == "string")
			e = eval(e);

		for(var x in e) {
			if (e[x])
				i++;
		}

		return i;
	};
	/* [IE, NN6]

		@param execludePatten : must be reg expression.
			ex- :([A-Z_]+)

		@param format "V" means value tag. ex: "={V}"
	    // store trailing whitespace, and only hand it over
	    // the next time round. Unless we hit a tag, then we kill it
	    if (this._buff) {
	        this._trailingWS = this._buff.match(/[ \t\n]*$/);
	        this._buff = this._buff.replace(/[ \t\n]*$/, '');
	    }
	*/
	// logs
	//		update: 2010-11-06 05:43:20		added "if(!prefix && typeo..."
	//
	function getElementPropertiesWithValue(e, format, regexp)
	{
        var prop_names = correctProperties(e);
        var result = "";
        if (regexp !== undefined && typeof regexp === "string") {
            regexp = new RegExp(regexp, "g");
        }
        if(!format)
            format = "={V}";

        for(var i = 0; i < prop_names.length; i++) {
            var prop = prop_names[i];
            if(regexp && regexp.test(prop)) //prop.match(regexp)
                continue;

            var v = prop;
            var o = e[ prop ];    // [2010-11-26 11:00:38] TODO: o is object のとき gepwv を call.
            var value = (typeof(o) === "function")? o.toString(): o;
            result += v + format.replace("V", value) + "\n";
        }

        return result;
	};


	// [2010-11-14 13:57:01] verify on FireFox 3.6
	//
	//		delegate instanceof Delegate "ERROR Delegate is not defined."
	//		delegate instanceof util.XGeneratorDelegate -> true.
	//
	//		util.XGeneratorDelegate.name -> Delegate...
	//
	// -----------------------------------------------------------------------------
	//
	//	interface Delegate.
	//
	// -----------------------------------------------------------------------------
	// 委譲先 (delegate)
	// preffix "X" は override が必要な抽象クラスであることをあらわす.
	/*
	usage:
	case: with JQuery

		var delegate = $.extend
		(
			new util.XGeneratorDelegate(),
			{
				//prepare: function(g) {}, // override is unnecessary
				execute: function(g) {
					var obj = g.object;
					// do something...
				},
				after: function(g) {
					$("#dialog").empty().html( g.getResult() )
						.effect("highlight").effect("highlight");
				}
			}
		);

	case: other

		var delegate = new util.XGeneratorDelegate();
		delegate.execute = function(g) {
			var obj = g.object;
			// do something...
		};
		delegate.after = function(g) {
			var obj = g.object;
			// do something...
		};

	*/
	// [2010-11-14 13:57:01] verify on FireFox 3.6
	//
	//		delegate instanceof Delegate "ERROR Delegate is not defined."
	//		delegate instanceof util.XGeneratorDelegate -> true.
	//
	//		util.XGeneratorDelegate.name -> Delegate...
	//
	function XGeneratorDelegate() {}
	XGeneratorDelegate.prototype = {
		prepare: $.noop,
		execute: $.noop,
		after: $.noop
	};
	// -----------------------------------------------------------------------------
	//
	//	class Generator.
	//
	// -----------------------------------------------------------------------------
	// 委譲 (delegation)
	//
	// @param delegate : util.XGeneratorDelegate instance
	//
	function Generator(delegate, obj)
	{
		this.object = obj,
		this.delegate = delegate;
	};
	Generator.prototype = {
		_ret:  "",
		//
		// unknown data, 使用する側のみ知っている.
		//
		object:  undefined,
		delegate:  undefined,
		//
		// 2010-11-14 12:28:01
		//
		process:  function()//{};
		{
			this.delegate.prepare(this);
			/*this._ret = */this.delegate.execute(this);
			this.delegate.after(this);
		},
		getResult:  function()
		{
			return this._ret;
		},

		//
		// can call Delegate.execute()
		//
		append:  function(product) { this._ret += product; },
		set:  function(product) { this._ret = product; },
		prepend:  function(product) { this._ret = product + this._ret; },
		reset:  function(product) { this._ret = ""; }
	};


	//
	// Tracker class. (Decorator
	//
	function Tracker(interval)
	{
		initializeAtom
		(
			this,
			acutual_ns.util.Tracker,
			acutual_ns.AfxObject,
			arguments, name_space + ".util"
		);
		if(arguments.length > 0) {
			if( isEnumerable(arguments[0]) ) {
				var actualArgs = arguments[0];
				this._interval = actualArgs[0];
			}
			else
				this._interval = arguments[0];
		}/**/
		else
			this._interval = interval;

		this._listeners = [];
	}
	// for Tracker class override it.
	function TrackingListener() {
		this.onTracking = $.noop;
	};

	//
	//
	//
	Tracker.prototype =
	{
		// private.
		_t: undefined,			// acutual_ns.logic.Thread object;
		_listeners: undefined,
		_started: false,
		/* default interval */
		_interval: 0,

		_run: $.noop,

		// public.
		/* Must call after "_run" defined. */
		init: function constructThread(data) {
			this._t = new(acutual_ns.logic.Thread)(this._run, data, this._interval, true);
		},
		// [2010-12-05 12:29:11] added.
		initDelegate: function constructDelegateThread(data) {
			this._t = new(acutual_ns.logic.DelegateThread)(this._run, data, this._interval, true);
		},
		setTimerate: function(t) { this._t.setTimerate(t); },
		getTimerate: function() { return this._t.getTimerate(); },

		tracking: function()
		{
			if(!this._started)
			{
				this._started = true;
				this._t.start();
			}
		},
		stop: function()
		{
			this._t.stop();
			this._started = false;
		},
		getTrackingListenerInstance: function(override_fn)
		{
			var l = new TrackingListener();
			typeof(override_fn) === "function" && (l.onTracking = override_fn);
			return l;
		},

		addTrackingListener: function(l) {
			//(l instanceof TrackingListener) && (this._listeners.push(l));
			/* 型に関して少し緩くした. */
			(typeof(l.onTracking) === "function") && (this._listeners.push(l));
		},
		dispatchListener: function(data) {
			var al = this._listeners;
			for(var i in al)
				al[i].onTracking(data);
		}
	};

/*
	class Entry<E> {
		E element;
		Entry<E> prev;
		Entry<E> tail;
	}
*/
	function LinkedList() {

		// tail, prev is Entry object.
		this.createEntry = function (e, tail, prev) {
			return {
				element: e,
				prev: prev,
				tail: tail
			};
		};

		this._getEntry = function (index) {
			if (index < 0 || index >= this.sz)
				throw new Error("Index: " + index + ", Size: " + this.sz);

			/*Entry<E>*/
			var e = this.header;
			if (index < (this.sz >> 1)) {
				for (var i = 0; i <= index; i++)
					e = e.tail;
			}
			else {
				for (var i = this.sz; i > index; i--)
					e = e.prev;
			}
			return e;
		};

		this._addBefore = function (e, entry) {
			var newEntry = this.createEntry(e, entry, entry.prev);
			newEntry.prev.tail = newEntry;
			newEntry.tail.prev = newEntry;
			this.sz++;
			return newEntry;
		};

		this._remove = function (e) {
			if (e == this.header)
				throw new Error("NoSuchElementException");

			var result = e.element;
			e.prev.tail = e.tail;
			e.tail.prev = e.prev;
			e.tail = e.prev = null;
			e.element = null;
			this.sz--;

			return result;
		};

		var h = this.createEntry(null, null, null);
		h.tail = h.prev = h;
		// initialize menbers.
		this.header = h;
		this.sz = 0;
	};

	LinkedList.prototype =
	{
		header: undefined,

		get: function(index) {
     	   return this._getEntry(index).element;
        },
		/*int*/			size: function() {
			return this.sz;
		},
		/*boolean*/		isEmpty: function() {
			return this.sz === 0;
		},
		/*boolean*/		contains: function(o) {
			return this.indexOf(o) !== -1;
		},
		/*boolean*/		add: function(/*E*/ e) {
			this._addBefore(e, this.header);
			return true;
		},
		/*boolean*/ 	remove: function(/*Object*/ o) {
			var h = this.header;
			var e;
			if (o === null) {
				for (e = h.tail; e != h; e = e.tail) {
					if (e.element === null) {
						this._remove(e);
						return true;
					}
				}
			} else {
				for (e = h.tail; e != h; e = e.tail) {
					if (o === e.element) {
						this._remove(e);
						return true;
					}
				}
			}
			/*if(e !== null)
			{
				this._remove(e);
				return true;
			}*/
			return false;
		},
		/*void*/		clear: function() {
			var h = this.header;
			var e = h.tail
			while (e != h) {
				var tail = e.tail;
				e.tail = e.prev = null;
				e.element = null;
				e = tail;
			}
			h.tail = h.previous = h;
			this.sz = 0;
		},
		/*int*/			indexOf: function (o) {
			var index = 0;
			var h = this.header;
			if (o == null) {
				for (var e = h.tail; e != h; e = e.tail) {
					if (e.element == null)
						return index;
					index++;
				}
			}
			else {
				for (var e = h.tail; e != h; e = e.tail) {
					if (o === e.element)
						return index;
					index++;
				}
			}
			return -1;
		},

		/*Iterator<E>*/	iterator: function() {
		},
		/*Object[]*/	toArray: function() {
		},
		/*<T> T[]*/		toArray: function(/*T[]*/ a) {
		},
		/*boolean*/		containsAll: function(/*Collection<?>*/ c) {
		},
		/*boolean*/ 	addAll: function(/*Collection<? extends E>*/ c) {
		},
		/*boolean*/ 	removeAll: function(/*Collection<?>*/ c) {
		},
		/*boolean*/ 	retainAll: function(/*Collection<?>*/ c) {
		},
		/*boolean*/		equals: function(/*Object*/ o) {
		},
		/*int*/			hashCode: function() {
		}
	};

	/* [2010-12-01 11:09:41] class CategorizedArrayList added.
		カテゴリ別インデックスリスト
	*/
	function CategorizedArrayList() {
		initializeAtom
		(
			this,
			acutual_ns.util.CategorizedArrayList,
			acutual_ns.AfxObject,
			arguments, name_space + ".util"
		);
		this.list = {};
	};

	//var _PREFIX = "h";
	// 2014-06-20 04:24:50 modify.
	function genHash(any) {
		!any && (any = ""); // means generate _PREFIX + "0".
		typeof any !== "string" && (any = any.toString());
		return "H" + any.hashCode();
	}
	CategorizedArrayList.prototype =
	{
		list: undefined,	// NOTE: [] は Array object, {} は Object...

		_getArray: function(category) {
			return this.list[genHash(category)];
		},
		// @return boolean :maybe always true (Collection.add の汎用規約
		add: function(obj, category) {
			var hash = genHash(category);
			var ar = this.list[hash];
			if(!ar)
			{
				ar = this.list[hash] = [];
				// [2010-12-02 16:22:38] the "category" bind to array object.
				ar.category = category;
			}
			// push returns length.
			return ar.push(obj) > 0;
		},
		// [2010-12-08 12:45:32] added.
		//
		// @param comp_fn	:arg0=obj, arg1=current point obj
		//
		indexOf: function(obj, category, comp_fn) {
			var ar = this._getArray(category);
			if(!ar)
				return -1;

			var l = ar.length;
			if(typeof(comp_fn) === "undefined")
			{
				for(var i = 0; i < l; i++)
				{
					if(ar[i] === obj)
						return i;
				}
			} else
			{
				for(var i = 0; i < l; i++)
				{
					if( comp_fn(obj, ar[i]) )
						return i;
				}
			}
			return -1;
		},
		//
		// @return tagged object {object: value, category: category}
		//
		getRandom: function() {	// [2010-11-19 14:46:21]
			//var hash = genHash(category);
			var l = this.list;
			var props = acutual_ns.util.cp(l);
			var tagged, ar;
			{
				var ci = Math.floor(Math.random() * props.length);
				ar = l[ props[ci] ];
				tagged = { object: undefined, category: ar.category };
			}
			var i = Math.floor(Math.random() * ar.length);
			tagged.object = ar[i];
			return tagged;
		},
		// callback は、要素の値、要素のインデックス、走査されている Array オブジェクトという
		// 3 つの引数をともなって呼び出されます。
		//		a.forEach(function(element, index, array) {});
		// @return null or obj next.
		//
		getNext: function(obj, category) {
			var ar = this._getArray(category);
			if(!ar)
				return null;

			var l = ar.length;
			for(var i = 0; i < l;)
			{ // ( cindex + 1 ) % length
				if(ar[i++] === obj)
					return ar[i % l];
			}
			return null;
		},
		get/*Ordinal*/: function(ord, category)
		{
			var ar = this._getArray(category);
			if(!ar)
				return null;
			if(ord < 0 || ord >= ar.length)
				return null;

			return ar[ord];
		},
		//
		// update category list by new_ar
		//
		updateCategory: function(new_ar, category) {
			/* update array */
			// [2010-12-02 16:22:38] the "category" bind to array object.
			new_ar.category = category;
			this.list[genHash(category)] = new_ar;
		},
		//
		// @return all entry count.
		//
		size: function() {
			var l = this.list;
			var count = 0;
			for(var p in l)
				count += l[p].length;
			return count;
		},
		//
		// @return entry count of category.
		//
		categorySize: function(category) {
			var ar = this._getArray(category);
			return ar? ar.length: 0;
		},
		//
		// @return array of YouTubeVideoEntry array list.
		//			array has "category" property.
		//
		categories: function() {
			var l = this.list;
			var cl = [];
			for(var p in l)
				cl.push(l[p]);
			return cl;
		},
		//
		// @return array of category name array.
		//
		listCategoryName: function() {
			var l = this.list;
			var cl = [];
			for(var p in l)
			{
				var ar = l[p];
				cl.push(ar.category);
			}
			return cl;
		},
		// [2010-12-08 13:21:32] added.
		// remove all added elements.
		//
		clear: function() {
			this.list = {};
		},
		//
		// @return removed entry.
		//
		remove: function(entry, category) {
			return this._getInternal(entry, category, true);
		},
		//
		// @return array of YouTubeVideoEntry
		//
		getCategory: function(category) {
			return this._getArray(category);
		},
		//
		// @return if sccess then true.
		//
		removeCategory: function(category) {
			return (delete this.list[genHash(category)]);
		},
		//
		// @return video id or playlist id, uid, entry
		//
		_getInternal: function(any, category, b_remove) {
			var ar = this._getArray(category);
			if(!ar)
				return null;

			var l = ar.length;
			var rv = null, update_ar = null;

			if(b_remove)
			{
				update_ar = ar.filter
				(
					function (o) { if(o === any) rv = o; return o !== any; }
				);
			}
			else
			{
				for(var i = 0; i < l;)
				{
					if(ar[i++] === any)
						return ar[i % l];
				}
			}

			if(update_ar !== null) {
				/* update array */
				// [2010-12-02 16:22:38] the "category" bind to array object.
				update_ar.category = category;
				this.list[genHash(category)] = update_ar;
			}
			return rv;
		}
	};

	function Stopwatch() {};
	//
	//	acutual_ns.logic.Stopwatch
	//
	Stopwatch.prototype = {
		st: 0,
		ed: 0,
		start: function() {
			this.st = new Date().getTime();
		},
		stop: function() {
			this.ed = new Date().getTime();// - this.st;
		},
		getResult: function() {
			return this.ed - this.st;
		},
		toString: function() {
			return "time spent(ms)=" + this.getResult();
		}
	};

	//
	// [2010-12-09 09:56:46] added.
	// TODO: さらに拡張して name space 以下のすべての階層を decode.
	//
	//decodeJs(window.yt, "\\[native code\\]", false);
	function decodeJs(e, exculude_exp)
	{
		var funcs = new Array();
		var fn_index = 0;

		if(typeof(exculude_exp) === "string")
			exculude_exp = exculude_exp.split("|");

		if(exculude_exp)
		{
			for(var idx in e)
			{
				var nnn = e[idx]
				if(typeof(nnn) === "function")
				{
					var fn_str = nnn.toString();
					var no_match = 1;
					for(var expIndex = 0; expIndex < exculude_exp.length; expIndex++)
					{
						//if( fn_str.match(exculude_exp[expIndex], "g") )
						if( fn_str.match(exculude_exp[expIndex], "g") )
						{
							no_match = 0;
							break;
						}
					}
					if(no_match === 1)
						funcs[fn_index++] = { name: idx, script: fn_str };//.replace(/</g, "&lt;");
				}
			}
		}
		else
		{
			for(var idx in e)
			{
				var nnn = e[idx]
				if(typeof(nnn) === "function")
					funcs[fn_index++] = { name: idx, script: nnn.toString() };//.replace(/</g, "&lt;");
			}
		}

		funcs.sort();
		return funcs;
	}


	// -------------------------------- recursive algorizum and linked list.
	//
	//	[2010-11-30 15:18:07]
	//
	// @param s		: jquery object or selector.
	// @param m		: the method of jquery fx or effect.
	// @param msub	: if m === "effect" then type of effect.
	// @param t		: the time of jquery fx.
	// @param fn	: pre execute function of jquery fx.
	//
	function fxProperties(s, m, msub, t, fn)
	{
		return {
			s/*elector*/: s,
			m/*ethod*/	: m,
			msub/*effect method*/	: msub,
			t/*ime*/	: t,
			prefn/*ime*/: fn,

			prev		: null,
			tail		: null
		};
	}
	//
	// @param context_arry : the array of fxProperties.
	//
	function fpChainEx(context_arry)
	{
		var fp_head, fp_current, fp_tail, context = context_arry.shift();
		if(!context)
			return null;

		/* context.s is undefined? */
		var subject = (context.s instanceof jQuery || !context.s)? context.s: context.s.trim();
		fp_head = fxProperties(subject, context.m, context.msub, context.t, context.prefn);
		fp_current = fp_head;
		while( (context = context_arry.shift()) )
		{
			subject = (context.s instanceof jQuery || !context.s)? context.s: context.s.trim();
			fp_tail = fxProperties(subject, context.m, context.msub, context.t, context.prefn);
			fp_current.tail = fp_tail;
			fp_tail.prev = fp_current;
			fp_current = fp_tail;
		}
		return fp_head;
	}
	// -------------------------------- recursive algorizum and linked list.
	//
	// [2010-12-06 10:40:43] added.
	// [2010-12-10 02:46:45] improve.
	//
	function animate_jqobj(fxp) {
		var fpc_ = fxp
		function recursive() {
			if(fpc_ === null) {
				return;
			}
			fpc_.prefn && fpc_.prefn();
			/* fpc_.s is undefined? */
			if(fpc_.s)
			{
				var jo = (fpc_.s instanceof jQuery)? fpc_.s: $(fpc_.s);
				//var postfn = function() { fpc_ = fpc_.tail; recursive(); };
				//var args = fpc_.msub? [fpc_.msub, fpc_.t, postfn]: [fpc_.t, postfn];
				var args = [fpc_.t, function() { fpc_ = fpc_.tail; recursive(); }];
				fpc_.msub && args.unshift(fpc_.msub);

				//args.push(fpc_.t);
				//args.push(function() { fpc_ = fpc_.tail; recursive(); });
				jQuery.fn[fpc_.m].apply(jo, args);
			}
			//fpc_ = fpc_.tail;
		}
		recursive();
	}
	// -------------------------------- recursive algorizum and linked list.


	// -----------------------------------------------------------------------------
	//
	//	Name space of acutual_ns.util
	//
	// -----------------------------------------------------------------------------
	//debugger;
	//$.extend(
		acutual_ns.util[_PACKAGE_EXTEND_METHOD_](
		{
			Tracker							: Tracker,

			LinkedList						: LinkedList,
			CategorizedArrayList			: CategorizedArrayList,

			XGeneratorDelegate				: XGeneratorDelegate,
			Generator						: Generator,
			//
			// usage:
			//	var sw = new acutual_ns.logic.Stopwatch();
			//	sw.start();
			//	// do something...
			//	sw.stop();
			//	var time = sw.getResult();
			//
			Stopwatch						: Stopwatch,

			fxPropertiesChain				: fpChainEx,
			jQueryAnimateRecursive			: animate_jqobj,
			decodeJs						: decodeJs,

			dumpArguments					: dumpArguments,
			correctProperties				: correctProperties,
			elementPropertySizeOf			: elementPropertySizeOf,
			getElementPropertiesWithValue	: getElementPropertiesWithValue,

			da	 : dumpArguments,				 /* <-- this is short name */
			cp	 : correctProperties,			 /* <-- this is short name */
			eps	 : elementPropertySizeOf,		 /* <-- this is short name */
			gepwv: getElementPropertiesWithValue,/* <-- this is short name */
			/** NOTE: 2014-03-03 23:40:49 implement. remove yahoo Advertising */
			removeYahooAD: function() {
				if (location.host !== "localhost") {
					$(
						"link[href*='bc.geocities.yahoo.co.jp']," +
						"script[src*='bc.geocities.yahoo.co.jp']," +
						"img[src*='bc.geocities.yahoo.co.jp'],"+
						"#y_gc_div_mast,#y_gc_div_au1,#y_gc_div_adcntr," +
						"script[language*='JavaScript'],img[src*='visit.geocities.jp'],noscript"
					).remove();
					// auWritten
					day = id = ie4 = ie5 = ns4 = ns6 = mac =  url = ref = undefined;
				}
			}
		});
	//);	// $.extend

	// -----------------------------------------------------------------------------
	//
	//	Name space of acutual_ns.io
	//
	// -----------------------------------------------------------------------------
	acutual_ns.io[_PACKAGE_EXTEND_METHOD_](
	{
		TextReader: function TextReader(data) {
			this.setContents(data);
		}
	});
	acutual_ns.io.TextReader.prototype = {
		//private.
		_contents: "",
		_offset: 0,
		_limit: 0,
		_separater: "\n",
		_eof: false,

		//public
		isEOF: function isEOF() { return this._eof; },
		reset: function reset() {
			this._eof = false;
			this._offset = 0;
		},
		setContents: function(data) {
			//if(!data)
			//	throw new Error("error, data is:[" + data + "]");
			var is_empty = (data === null || !data);
			this._contents = (is_empty)? "": data;
			//this._offset = 0;
			this._limit = (is_empty)? 0: data.length;
			if (!is_empty)
				this._separater = /\r\n/g.test(data)? "\r\n": "\n";
			this.reset();
		},
		readLine: function readLine()
		{
			var contents = this._contents;
			var start = this._offset;
			var i = contents.indexOf(this._separater, start);
			if(i === -1)
			{
				if(start >= this._limit)
					return null;
				else
				{
					i = this._limit;	// 最後に改行文字がない.
					this._eof = true;
				}
			}

			this._offset = i + this._separater.length;
			return contents.substring(start, i);
		}
	};

	// -----------------------------------------------------------------------------
	//
	//	Name space of util.storage
	//
	// -----------------------------------------------------------------------------
	acutual_ns.storage[_PACKAGE_EXTEND_METHOD_](
	{
		//
		//	string resource etc, 軽量な class.
		//	resource が大量になる場合は util.Properties の使用がおすすめ.
		//
		Resource: function Resource() {
			this._datas = {};
		}
	});
	acutual_ns.storage.Resource.prototype =
	{
		size: function size() {
			return acutual_ns.util.eps(this._datas);
		},
		getResource: function (key) {
			return this._datas[key];
		},
		/**
		 * data が存在するか?
		 */
		contains: function(data) {
			var cache = this._datas;
			for (var name in cache) {
				if (cache[name] === data)
					return true;
			}
		},
		/** [2014-06-06 16:26:44]
		 * data string に \uxxxx 形式の unicode escape が含まれている場合,
		 * eval で評価することにより native javascript engine が解除してくれる.
		 *
		 * NOTE: 2014-06-06 16:34:07
		 *   html data の場合, "<" などで error となるので適宜 escape しておくか,
		 *   この function を使わないようにする.
		 */
		evalString: function(key) {
			var contents = this._datas[key];
			return (contents !== undefined) ? eval(contents): null;
		},
		/** [2014-06-06 16:26:44]
		 * data string に \uxxxx 形式の unicode escape が含まれている場合,
		 * eval で評価することにより native javascript engine が解除してくれる.
		 *
		 * NOTE: 2014-06-06 16:34:07
		 *   html data の場合, "<" などで error となるので適宜 escape しておくか,
		 *   この function を使わないようにする.
		 *
		 * NOTE: 2014-06-18 09:56:07
		 *   JSON.stringify を使って正規化すればよいかもしれない.
		 */
		escapHTMLMinimum: function(key) {
			var contents = this._datas[key];
			return (contents !== undefined) ?
			contents.replace(/(<)|(>)|(")/g, function(b, lt, gt, quot) {
				//var l = arguments.length;
				//for (var i = 0; i < l; i++)
				//	console.log("arguments[" + i + "]=" + arguments[i]);
				if (lt)
					return "&lt;";
				if (gt)
					return "&gt;";
				if (quot)
					return "&quot;";
			}): null;
		},
		//
		//	@param key :store key for loaded data. (Expected string
		//	@param url :data url.
		//
		load: function (key, url) {
			// XMLHttpRequest object を使うこの関数はこの場合 UTF-8 encode としておけば
			// 正しく decode 表示される.(?) [2010-11-06 11:09:45] sjis などは文字化け
			var _this = this;
			$.get
			(
				url, null, function(responseText, status, xhr)
				{
					if(status === "success") {
						_this._datas[key] = responseText;
					}
					else
						alert("Error Resource.load: " + status);
						//$gw.trigger(ytctrl.events.LOG, "Error Resource.load: " + status);
				}
			);
		},
		/**
		 * @param data :any data.
		 * @param key  :store key for loaded data. (Expected string
		 * @return     random key will be generated automatically if you do not specify a key.
		 */
		add: function (data, key) {
			!key && (key = generateId(8));
			this._datas[key] = data;
			return key;
		},
		/** remove entry */
		remove: function (key) {
			return delete this._datas[key];
		}
	};

	// -----------------------------------------------------------------------------
	//
	//	Name space of acutual_ns.logic
	//
	// -----------------------------------------------------------------------------
	var _TIMER_DELEGATE_URI = "script/external/timer-delegate.js";
	acutual_ns.logic[_PACKAGE_EXTEND_METHOD_](
	{
		//
		// acutual_ns.logic.Thread object.
		//
		//   use: new acutual_ns.logic.Thread("method", <function object>);
		//
		/*
			new ytctrl.logic.Thread
			(
				fn, data, 4000
			).start().stopLater(2000);
		*/
		Thread: function Thread(fn, data, time_rate, b_loop) {
			// privete.
			this._fn = fn;
			this._data = data;
			/* time_rate = 0 は意味がないので, 最低は 1ms 固定. */
			this._time = (typeof(time_rate) === "number" && time_rate > 0)? time_rate: 1;

			this._type = b_loop? "Interval": "Timeout";
		},
		/* [2010-12-05 10:10:50] test proposed. */
		DelegateThread: function DelegateThread(fn, data, time_rate, b_loop) {

	    	var _super = acutual_ns.logic.Thread;
			_super.call(this, fn, data, time_rate, b_loop);

			/* validate function */
			var function_body = typeof(this._fn) === "function"? this._fn: $.noop;
			this._fn = function_body;

			var worker = new Worker(_TIMER_DELEGATE_URI);
			worker.addEventListener
			(
				"message",
				function (event) {
					function_body(data)
				}, true
			);
			// ワーカー内でのエラーを捕捉しログに出力
			worker.addEventListener("error", function(){} , true);
			this._worker = worker;
		}
	});
	//
	//	acutual_ns.logic.Thread
	//
	acutual_ns.logic.DelegateThread.prototype = {
		// privete.
		_worker: undefined,

		// public.
		/* [2010-12-05 11:12:37] first impression.
			1.	自分の環境 (Pentium3 3Ghz) では 20ms くらいが限界のようだった.
				10ms にすると window UI に割り込むことがかなり難しい状況.

			2.	Worker に delegate しないで実行したほうが(Thread) パフォーマンスは良かった.
				1 ms でも UI 割り込みは余裕があった.

			3.	このことから Worker では message event でコストが高いため
				短いサイクルでの大量コールは全く向いてない.(と思われる
		*/
		start: function()
		{
			this._worker.postMessage
			(
				{ interval: this._time, type: this._type, method: "start" }
			);
			return this;
		},
		//
		stop: function() {
			this._worker.postMessage
			(
				{ type: this._type, method: "stop" }
			);
		}
	};

	//
	//	acutual_ns.logic.Thread
	//
	acutual_ns.logic.Thread.prototype = {
		// privete.
		_time: 0,
		_type: undefined,
		_fn: undefined,
		_data: undefined,

		// public.
		setTimerate: function(time) {
			this._time = time;
			this.stop();
			this.start();
		},
		getTimerate: function() { return this._time; },
		start: function()
		{
			if(this._tid)	/* important! */
				return;

			var _this = this, function_body = typeof(this._fn) === "function"? this._fn: $.noop;
			/*In this case, seems to be a good idea to keep running once before. */
			if( this._type === "Interval" )
				function_body(this._data);

			/* Web Workers 用に 書き直す. (window object は存在しない) */
			this._tid = W["set" + this._type]
			(	/* setTimeout, scope に注意. */
				function() {
					function_body(_this._data);
				}, this._time
			);
			return this;
		},
		//
		stop: function() {
			if(!this._tid) return;
			W["clear" + this._type](this._tid);
			this._tid = undefined;
		},
		// Must be "setTimeout", not a "setInterval".
		stopLater: function(time)
		{
			var _this = this;
			if(!time)
				time = 3000;
			setTimeout
			(
				function() { _this.stop(); }, time
			);
		}
	};
	/* extend */
	acutual_ns.oop.extendOverride
	(
		acutual_ns.logic.DelegateThread.prototype, acutual_ns.logic.Thread.prototype
	);


	//
	// ------------------------------- define name space classes.----------------------------
	//
	/* this class is low level. */
	acutual_ns.Class = function( instance )
	{
		// private.
		this._name = lookUpCanonicalName(instance.constructor);
		this._inheritanceList = lookUpInheritanceList(instance.constructor);

	};
	acutual_ns.Class.prototype = {
		getName: function getClass() {
			return this._name;
		},
		isInheritance: function isInheritance(qname) {
			var list = this._inheritanceList;
			for(var i in list) {
				if(list[i] === qname)
					return true;
			}
			return false;
		}
	};

	// AfxObject interface.
	// this class is root.
	/*
		[2010-11-26 00:40:07]
			すべてのクラスの親.

			制約として 引数に tag 付け object をつかって初期化する?
	*/
	var AFX_OBJ_LITERAL = name_space + ".AfxObject";
	acutual_ns.AfxObject = function AfxObject()
	{
		var list = [AFX_OBJ_LITERAL];
		for(var i = 0; i < arguments.length; i++) {
			var arg = arguments[i];
			if(typeof(arg) !== "string")
				break;

			arg.length > 0 && list.push(arg); // push returns current size?
		}
		// assing as static.
		//if( !acutual_ns.oop.isInheritanceAssigned(acutual_ns.AfxObject) )
			acutual_ns.oop.assignInheritance(this, list);
	};
	// static.
	acutual_ns.oop.assignQName(acutual_ns.AfxObject, name_space);
	acutual_ns.AfxObject.prototype =
	{
		getClass: function getClass() {
			return new acutual_ns.Class(this);
		},
		instanceOf: function instanceOf(constructor) {
			var list = acutual_ns.oop.lookUpInheritanceList(this.constructor);
			for(var i in list)
			{
				if(eval(list[i]) === constructor)
					return true;
			}
			return false;
		}
	};

	// Visitor interface.
	/*var Visitor =*/
	acutual_ns.IVisitor = function IVisitor()
	{
		initializeAtom(
			this,
			acutual_ns.IVisitor,
			acutual_ns.AfxObject,
			arguments, name_space
		);

		//this.name = name_space + ".IVisitor";
	};
	acutual_ns.IVisitor.prototype =
	{
		visit: $.noop
	};

	acutual_ns.XApplication = function XApplication()
	{
//		debugger;
		initializeAtom(
			this,
			acutual_ns.XApplication,
			acutual_ns.AfxObject,
			arguments, name_space
		);
		if(arguments.length > 0 && isEnumerable(arguments[0]))
		{
//			var actualArgs = arguments[0];
			//this._m = actualArgs[0];
		}
		//this.name = name_space + ".IVisitor";
	};
//	acutual_ns.oop.assignQName(acutual_ns.XApplication, name_space);


	/*
	App = new jsafx.XApplication();
	Appclass = App.getClass();
	App.warning();
	App.alert();
	*/
	acutual_ns.XApplication.prototype =
	{
		//IDomain
		getBelongingDomain: $.noop,
		//void
		setBelongingDomain: $.noop,

		//void
		runApplication: $.noop,
		//void
		dispose: $.noop,

		//IIconManager
		getIconManager: $.noop,
		//void
		acceptPlugin: $.noop,//(IPlugin plugin);
		//void
		addPluginMenu: $.noop,//(JMenuItem item);

		//public void
		openFileEvent: $.noop,
		//public void
		saveFileEvent: $.noop,
		//public boolean
		onFileOpen: $.noop,//(File[] f);
		//public boolean
		onFileSave: $.noop,//(File f);

		/**
		 * The alert message is displayed to the user.
		 * @param msg  attention message.
		 */
		//public void
		alert: function alert(msg)
		{
			var content = "<div class='ui-state-highlight ui-corner-all' style='padding: 0pt 0.7em;'>" +
			"<p style='padding: 2px; margin: 2px;'><span class='ui-icon ui-icon-info' style='" +
			"float: left; margin-right: 0.3em;'></span>" +
			"<strong>Warning: </strong>" + msg + "</p></div>";

			var $dlg = $( "<div title='Application warning.'/>" );
			$dlg.dialog(
			{
				autoOpen: false,
				dialogClass: 'ui-state-highlight',
				position: [10, 45],
				width: 235,
				close: function() {
					$dlg.remove();
				}
			});
			$dlg.dialog("open").html(content).effect("highlight");
		},

		/**
		 * The explanation window of the application is displayed.
		 */
		//public void
		about: $.noop,

		/**
		 * That shows status of currently.
		 * @param state Character string that shows state.
		 */
		//public void
		showStatus: $.noop,//(String state);

		/**
		* The message whose meaning is stronger than the alert is displayed.
		* @param msg   warning message.
		*/
		//public void
		warning: function warning(msg)
		{
			var content = "<div class='ui-state-error ui-corner-all' style='padding: 0pt 0.7em;'>" +
			"<p style='padding: 2px; margin: 2px;'><span class='ui-icon ui-icon-alert' style='" +
			"float: left; margin-right: 0.3em;'></span>" +
			"<strong>Warning: </strong>" + msg + "</p></div>";

			var $dlg = $( "<div title='Application warning.'/>" );
			$dlg.dialog(
			{
				autoOpen: false,
				dialogClass: 'ui-state-error',
				position: [10, 45],
				width: 235,
				close: function() {
					$dlg.remove();
				}
			});
			$dlg.dialog("open").html(content).effect("highlight");
		}
	};
	/*acutual_ns.IFeedVisitor.prototype = {
		visitFeed: $.noop,
		get method() { return this._m; },
		set method(m) { this._m = m; },
		get subject() { return this._s; },
		set subject(s) { this._s = s; }
	};*/


})(_PRIME_PACKAGE_NAME_); // end of (function()

/* [2010-11-26 07:49:00] 初期テスト OK
mydebug = new jsafx.DebuggerLite
mydebug.debugPane = "#textareas textarea";
mydebug.showErrorDlg(jsafx.util.gepwv(mydebug));
mydebug.printDebugPane(jsafx.util.gepwv(mydebug));
mydebug.log(jsafx.util.gepwv(mydebug));

mydebug.genStackTrace(mydebug.genStackTrace);
*/
(function(name_space)
{
	//
	var acutual_ns = eval(name_space);

	//var debugger_dialog_selector, debugger_pane_selector;

	//
	//
	//
	acutual_ns.DebuggerLite = function DebuggerLite() {};
/*
[2010-12-01 13:51:30] proposed.
window.onkeydown = function(e) { alert(e.keyCode); };

window.onkeydown = function(e) {
	$dom("counter").innerHTML = "typed key, code: 0x" + e.keyCode.toString(16);
};
window.onkeydown = function(e) {
	Options.DEFAULT_ERR_HANDLER(e);
};
*/
	acutual_ns.DebuggerLite.prototype = {
		//
		// Constants.
		//
		ENABLE: true,

		// private.
		_dialog_selector: undefined,
		_pane_selector: undefined,

		// public.
		//
		// @return jQuery object.
		//
		/*get debugDialog() {
			if( this._dialog_selector === undefined )
				return;

			return jQuery( this._dialog_selector );
		},*/
		//
		// @param selector :selector of jQuery object.
		//
		set debugDialog(selector) {
			this._dialog_selector = selector;
			$( selector ).dialog(
			{
				autoOpen: false,
				dialogClass: 'alert',
				//position: [10, 260],
				//width: 235,
				// The effect to be used. Possible values:
				//		'blind', 'bounce', 'clip', 'drop', 'explode', 'fold', 'highlight',
				//		'puff', 'pulsate', 'scale', 'shake', 'size', 'slide', 'transfer'.
				//
				//show: "clip",
				//hide: "clip"
			});
		},

		//
		// @return jQuery object.
		//
		get debugPane() {
			if( this._pane_selector === undefined )
				return null;

			return jQuery( this._pane_selector );
		},
		//
		// @param selector :selector of jQuery object.
		//
		set debugPane(selector) { this._pane_selector = selector; },
		// -----------------------------------------------------------------------------
		// for debag use.
		// -----------------------------------------------------------------------------
		//
		// [2010-11-06 05:30:10] for debug.
		//
		showErrorDlg: function sed(msg)
		{
			var d_selector = this._dialog_selector;
			var removable;// = false;
			var $dlg;
			if( d_selector === undefined )
			{
				removable = true;
				d_selector = "<div id='debug_dlg' title='debug infomation.'/>";
			} else removable = undefined;

			$dlg = $(d_selector);
			if(removable)
				$dlg.dialog(
				{
					autoOpen: false,
					dialogClass: 'alert',
					/*open: function() {
						$playlist_title.focus();
					},*/
					close: function() {
						$dlg.remove();
					}
				});

			//jQuery( this._dialog_selector ).dialog("open").empty()
			$dlg.dialog("open").empty()
				.html("<pre class='explain'>" + msg.escapeHTML() + "</pre>")
				.effect("highlight", {});
		},
		//
		// @param e: object(Error or any) or string.
		//
		printDebugPane: function pdp(e)
		{
			if( this._pane_selector === undefined )
				return;
			if(!this.ENABLE)
				return;
			if( typeof(e) === "object" || typeof(e) === "function" )
			{
				//this.log("typeof e:" + (typeof e) + ", typeof arguments[0]:" + (typeof arguments[0]));
				e = acutual_ns.util.gepwv(arguments[0]);
			}
			else e = new String(e);	/* convert undefined to "undefined"... */

			// Anonymous function name is empty string.
			var cn = this.printDebugPane.caller.name;
			var dp = jQuery( this._pane_selector );
			var method = "prepend";
			var content;
			if(typeof (dp[0].type) === "string")	/* means form object? */
			{
				content = ("caller <" + (cn? cn: "anonymous") + ">: " + e);
				method = "val";
			}
			else	// not form element e.g. textarea, input text
			{
				content = "<pre class='explain'>" +
							("caller &lt;" + (cn? cn: "anonymous") +
							"&gt;: <span class='errormsg'>" + e.escapeHTML() + "</span>")
							+ "</pre>";
			}

			dp[method](content);
			/*if(typeof e !== "string")
				this.showErrorDlg
				(
					acutual_ns.util.gepwv(e)
				);*/
		},

		//
		// @param text: message.
		// @param must: if always log message, need to "true".
		//
		// [2010-11-08 05:21:50] support colored text, like "#FFDab9,this is a message..."
		//
		log: function log(text, must)
		{
			if( this._pane_selector === undefined )
				return;
			if(!this.ENABLE && !must)
				return;

			if(!text)
				text = arguments.callee;

			var content;
			var matchs = (typeof(text) === "string")? text.match(/(#[0-9A-Fa-f]{6}),([\s\S]+)/): text;
			if(matchs !== null && matchs instanceof Array)	// set color to message.
			{
				content = "<span style='color:" + matchs[1] + "'>" + matchs[2] + "</span>";
			}
			else content = text;

			var dp = jQuery( this._pane_selector );
			var method = "prepend";
			if(typeof (dp[0].type) !== "string")
			{
				content = "<pre class='explain'>" + content/*no! .escapeHTML()*/ + "</pre>";
			}
			else method = "val";

			dp[method](content);
		},
		genStackTrace: function gst(fnobj)
		{
			var stack = "Stack trace:";
			var startname = fnobj.caller.name;
			!startname && (startname = "anonymous");

			while (fnobj) {
				var cn = fnobj.name;
				!cn && (cn = "anonymous");
				stack += "\n\t" + cn;
				fnobj = fnobj.caller;
			}

			this.log
			(
				"generate stack trace from: {" + startname + "}, trace :" +
				"\n" + stack
			);
		}
	};

})(_PRIME_PACKAGE_NAME_);



// remove variable.	[2010-11-26 03:02:25] FF cannot delete.
delete _PRIME_PACKAGE_NAME_;


